<?php
declare(strict_types=1);

namespace app\process;

use app\service\Jt808Decode;
use app\model\GpsRealtime;
use support\Redis;
use Workerman\Connection\UdpConnection;
use Workerman\Worker;

/**
 * Jt808Udp
 * - 校验：反转义后进行异或校验（最后1字节），在解密前验证；
 * - 解密：仅当 AES_ENABLE=1 时尝试 AES-128-ECB(PKCS#7) 对消息体解密；
 * - 解析：标准 JT808 头部与 0x0200 定位体结构；
 * - 指标：使用 Redis INCR 统计，避免多进程 cache() 丢计数。
 */
class Jt808Udp
{
    /** @var Worker */
    protected Worker $worker;

    public function onWorkerStart(Worker $worker): void
    {
        $this->worker = $worker;
        echo "JT808 UDP worker started on {$worker->name}\n";
    }

    public function onMessage(UdpConnection $connection, string $data): void
    {
        try {
            $decoder = new Jt808Decode(env('AES_KEY', '0123456789abcdef'));
            $msg = $decoder->decode($data);

            // 仅在校验与解析成功后更新指标（带 Redis 容错）
            try {
                Redis::incr('jt808:recv_packets');
                Redis::set('jt808:last_packet_at', date('Y-m-d H:i:s'));
            } catch (\Throwable $e) {
                // Redis 不可用时忽略指标写入，避免进程崩溃
            }

            if ($msg['msg_id'] === 0x0200) {
                $loc = $decoder->parse0200($msg['body']);

                $wgs_lat = $loc['lat'] / 1e6;
                $wgs_lon = $loc['lon'] / 1e6;

                GpsRealtime::upsertRealtime(
                    (string)$msg['terminal'],
                    $wgs_lat,
                    $wgs_lon,
                    (int)$loc['speed'],
                    (int)$loc['direction'],
                    (int)$loc['alt'],
                    (int)$loc['alarm'],
                    (int)$loc['acc'],
                    (int)$loc['located'],
                    (string)$loc['gpstime']
                );
            }
        } catch (\Throwable $e) {
            // 解析失败计数（带 Redis 容错）
            try {
                Redis::incr('jt808:decode_errors');
                Redis::set('jt808:last_error', substr($e->getMessage(), 0, 200));
            } catch (\Throwable $e2) {
                // Redis 不可用时忽略指标写入
            }
            echo "UDP decode error: {$e->getMessage()}\n";
        }
    }

    public function onWorkerStop(Worker $worker): void
    {
        echo "JT808 UDP worker stopped\n";
    }
}